/*
 * edbtool2_cheat_edb.c - edbtool2 fake edb library for snapshot editing
 * Clunix, cezanne@clunix.com, 2005.7
 *
 * Copyright (c) 2001-2005 by Clunix Inc. All Rights Reserved.
 */

#include "config.h"

#include "edbtool2.h"
#include "eds.h"
#include "et2_edb.h"

typedef edb_err_t (*executer_t)(sr_t *sr, sr_t **psr_res, ecm_ptr_t ctx);

static sr_walk_res_t
copy_walk(sr_t *sr_dst, sr_t *sr_src, ecm_ptr_t ctx)
{
	eds_set_owner(sr_dst, eds_get_owner(sr_src));
	eds_set_attr_update(sr_dst, eds_get_attr_update(sr_src));
	eds_set_attr_fetch(sr_dst, eds_get_attr_fetch(sr_src));
	eds_set_attr_system(sr_dst, eds_get_attr_system(sr_src));
	eds_set_reactors(sr_dst, eds_get_reactors(sr_src));
	if (!sr_is_group(sr_dst))
		sr_setcpy_val(sr_dst, sr_get_val(sr_src));
	return SR_WALK_OK;
}

static ECM_INLINE edb_err_t
do_all_child_ptrs(sr_t *sr_ptrs, executer_t executer, ecm_ptr_t ctx, sr_t **psr_res)
{
	sr_t	*sr_ptr, *sr_nextptr;
	sr_t	*sr_child;
	sr_t	*sr_res, *sr_res_one;
	int	num_child;
	edb_err_t	err;

	if ((num_child = sr_get_num_child(sr_ptrs)) <= 0)
		return -ERR_EDB_NOTEXIST;

	sr_res = sr_create_dir();
	for (sr_ptr = sr_first(sr_ptrs); sr_ptr; sr_ptr = sr_nextptr) {
		sr_nextptr = sr_next(sr_ptr);
		sr_child = (sr_t *)sr_get_ptr(sr_ptr);

		if ((err = executer(sr_child, &sr_res_one, ctx)) != EDB_OK)
			break;
		sr_append(sr_res, sr_res_one);
	}
	sr_free(sr_ptrs);
	if (err == EDB_OK) {
		if (psr_res)
			*psr_res = sr_res;
		else
			sr_free(sr_res);
		return EDB_OK;
	}
	sr_free(sr_res);
	return err;
}

edb_err_t
edb_get_field_fake(et2_edb_t *pet2_edb, edb_field_t edb_field, const char *LNP, const char *EDExpr, int opt, sr_t **psr_ret)
{
	sr_t	*sr_ptrs, *sr_ptr;
	sr_travopt_t	travopt = 0;
	edb_err_t	err = -ERR_EDB_NOTEXIST;

	if (EDExpr != NULL)
		return -ERR_EDB_NOTSUPPORTED;

	if (opt & SR_NO_DEREF)
		travopt = SR_TRAV_NO_DEREF;

	sr_ptrs = sr_traverse(pet2_edb->sr_cwd, LNP, NULL, NULL, travopt);
	if (sr_get_num_child(sr_ptrs) > 0) {
		sr_t	*sr, *sr_res;

		sr_res = sr_create_dir();
		SR_FOREACH_CHILD(sr_ptrs, NULL, sr_ptr) {
			sr = sr_walk_dup(sr_get_ptr(sr_ptr), copy_walk, NULL, opt);
			sr_append(sr_res, sr);
		}
		*psr_ret = sr_res;
		err = EDB_OK;
	}
	ecm_free(sr_ptrs);
	return err;
}

edb_err_t
edb_get_modinfos_fake(et2_edb_t *pet2_edb, sr_t **psr_ret)
{
	sr_t	*sr_modinfos;

	sr_modinfos = sr_getc(pet2_edb->sr_snapshot_conf, "modules");
	if (sr_modinfos == NULL)
		return -ERR_EDB_NOTEXIST;
	*psr_ret = sr_dup(sr_modinfos);
	return EDB_OK;
}

static edb_err_t
set_sr_val(sr_t *sr, sr_t **psr_res, ecm_ptr_t ctx)
{
	sr_val_t	val;

	if (!sr_casrv_scan((const char *)ctx, sr->type, &val))
		return -ERR_EDB_WRONGASRV;
	sr_set_val(sr, val);
	*psr_res = NULL;
	return EDB_OK;
}

static edb_err_t
set_sr_reactor(sr_t *sr, sr_t **psr_res, ecm_ptr_t ctx)
{
	char		*edexpr = (char *)ctx;
	sr_t		*sr_edexprs;

	if (ecm_empty_str(edexpr))
		sr_edexprs = NULL;
	else {
		sr_edexprs = edl_get_edexpr(edexpr, NULL, NULL);
		if (sr_edexprs == NULL)
			return -ERR_EDB_WRONGEDEXPR;
	}

	eds_set_reactors(sr, sr_edexprs);
	sr_free(sr_edexprs);

	*psr_res = NULL;
	return EDB_OK;
}

static edb_err_t
set_sr_owner(sr_t *sr, sr_t **psr_res, ecm_ptr_t ctx)
{
	sr_val_t	val;

	if (!sr_asrv_scan((char *)ctx, ST_XID, &val))
		return -ERR_EDB_WRONGASRV;
	*psr_res = NULL;
	eds_set_owner(sr, val.lval);
	return EDB_OK;
}

static edb_err_t
set_sr_attr_update(sr_t *sr, sr_t **psr_res, ecm_ptr_t ctx)
{
	sr_val_t	val;

	if (!sr_asrv_scan((char *)ctx, ST_ATTR_UPDATE, &val))
		return -ERR_EDB_WRONGASRV;
	*psr_res = NULL;
	eds_set_attr_update(sr, val.ival);
	return EDB_OK;
}

static edb_err_t
set_sr_attr_fetch(sr_t *sr, sr_t **psr_res, ecm_ptr_t ctx)
{
	sr_val_t	val;

	if (!sr_asrv_scan((char *)ctx, ST_ATTR_FETCH, &val))
		return -ERR_EDB_WRONGASRV;
	*psr_res = NULL;
	eds_set_attr_fetch(sr, val.ival);
	return EDB_OK;
}

edb_err_t
edb_set_field_fake(et2_edb_t *pet2_edb, edb_field_t field, const char *LNP, const char *EDExpr, const char *casrv, int opt)
{
	sr_t		*sr_ptrs = NULL;
	char		*asrv;
	sr_travopt_t	travopt = 0;
	edb_err_t	err = -ERR_EDB_NOTEXIST;
	executer_t	executer = NULL;

	if (EDExpr != NULL)
		return -ERR_EDB_NOTSUPPORTED;

	asrv = ecm_strdup(casrv);

	if (opt & SR_NO_DEREF)
		travopt = SR_TRAV_NO_DEREF;

	switch (field) {
	case EDB_FIELD_VAL:
		executer = set_sr_val;
		break;
	case EDB_FIELD_REACTOR:
		executer = set_sr_reactor;
		break;
	case EDB_FIELD_OWNER:
		executer = set_sr_owner;
		break;
	case EDB_FIELD_ATTR_UPDATE:
		executer = set_sr_attr_update;
		break;
	case EDB_FIELD_ATTR_FETCH:
		executer = set_sr_attr_fetch;
		break;
	case EDB_FIELD_ATTR_SYSTEM:
		err = -ERR_EDB_NOTALLOWED;
		break;
	default:
		err = -ERR_EDB_WRONGFIELD;
		break;
	}

	if (executer) {
		sr_ptrs = sr_traverse(pet2_edb->sr_cwd, LNP, NULL, NULL, travopt);
		err = do_all_child_ptrs(sr_ptrs, executer, asrv, NULL);
	}

	ecm_free(asrv);
	return err;
}

edb_err_t
edb_create_sr_fake(et2_edb_t *pet2_edb, const char *LNP, const char *EDExpr, sr_t *sr)
{
	sr_t	*sr_new, *sr_LNP, *sr_lastLNI;
	sr_t	*sr_ptrs, *sr_ptr;
	const char	*newname;
	edb_err_t	err = -ERR_EDB_NOTEXIST;

	if (EDExpr != NULL)
		return -ERR_EDB_NOTSUPPORTED;

	sr_LNP = get_sr_LNP(LNP);
	sr_lastLNI = sr_get_last(sr_getc(sr_LNP, "LNIs"));
	if (sr_getc_int(sr_lastLNI, "Type") != LNI_TYPE_NAME ||
	    (newname = sr_getc_str(sr_lastLNI, "Name")) == NULL) {
		sr_free(sr_LNP);
		return -ERR_EDB_INVALIDLNP;
	}

	sr_ptrs = sr_traverse(pet2_edb->sr_cwd, LNP, NULL, NULL, SR_TRAV_CREATE | SR_TRAV_GETPARENT | SR_TRAV_ABSENTONLY);
	if (sr_get_num_child(sr_ptrs) > 0) {
		SR_FOREACH_CHILD(sr_ptrs, NULL, sr_ptr) {
			sr_new = sr_dup(sr);
			sr_set_name(sr_new, newname);
			sr_append(sr_get_ptr(sr_ptr), sr_new);
		}
		err = EDB_OK;
	}
	sr_free(sr_LNP);
	sr_free(sr_ptrs);
	return err;
}

edb_err_t
edb_del_fake(et2_edb_t *pet2_edb, const char *LNP, const char *EDExpr, int opt)
{
	sr_t	*sr_ptrs, *sr_ptr;
	edb_err_t	err = -ERR_EDB_NOTEXIST;

	if (EDExpr != NULL)
		return -ERR_EDB_NOTSUPPORTED;
	sr_ptrs = sr_traverse(pet2_edb->sr_cwd, LNP, NULL, NULL, 0);
	if (sr_get_num_child(sr_ptrs) > 0) {
		SR_FOREACH_CHILD(sr_ptrs, NULL, sr_ptr)
			sr_free(sr_get_ptr(sr_ptr));
		err = EDB_OK;
	}
	sr_free(sr_ptrs);
	return err;
}

edb_err_t
edb_cd_fake(et2_edb_t *pet2_edb, const char *LNP, const char *EDExpr, char **pcwd)
{
	sr_t	*sr_res;

	if ((sr_res = sr_traverse_1(pet2_edb->sr_cwd, LNP, 0)) == NULL)
		return -ERR_EDB_NOTEXIST;
	pet2_edb->sr_cwd = sr_res;
	*pcwd = sr_get_LNP(sr_res);
	return EDB_OK;
}

edb_err_t
edb_snapshot_fake(et2_edb_t *pet2_edb)
{
	if (eds_take_snapshot(pet2_edb->snapshot) == EDS_OK)
		return EDB_OK;
	return -ERR_EDB_GENERAL;
}
